package com.example.array;

/**
 * 已知存在一个按非降序排列的整数数组 nums ，数组中的值不必互不相同。
 *  在传递给函数之前，nums 在预先未知的某个下标 k（0 <= k < nums.length）上进行了 旋转 ，
 *  使数组变为 [nums[k],nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]（下标 从 0 开始 计数）。
 *  例如， [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4] 。
 *
 *  给你 旋转后 的数组 nums 和一个整数 target ，请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值
 * target ，则返回 true ，否则返回 false 。
 *
 *  示例 1：
 * 输入：nums = [2,5,6,0,0,1,2], target = 0
 * 输出：true
 *
 *  示例 2：
 * 输入：nums = [2,5,6,0,0,1,2], target = 3
 * 输出：false
 */
public class Leetcode81_SearchII {
    public static void main(String[] args) {
        int[] nums = {2, 5, 6, 0, 0, 1, 2};
        int target = 0;
        target = 3;

        nums = new int[] {1, 0, 1, 1, 1};
        target = 0;
        System.out.println(new Solution().search(nums, target));
    }

    static class Solution {
        /**
         * 数组中有重复元素的情况，二分查找时可能会有 nums[left]=nums[mid]=nums[right]，
         * 此时无法判断区间 [left,mid] 和区间 [mid+1,right] 哪个是有序的。
         *
         * 例如 nums=[3,1,2,3,3,3,3]，target=2，首次二分时无法判断区间 [0,3] 和区间 [4,6] 哪个是有序的。
         * 对于这种情况，此时只能将当前二分区间的左边界加一，右边界减一，然后在新区间上继续二分查找。
         *
         * @param nums
         * @param target
         * @return
         */
        public boolean search(int[] nums, int target) {
            int left = 0, right = nums.length - 1;

            while (left <= right) {
                int mid = (left + right) >> 1;
                if (nums[mid] == target) return true;

                if ((nums[left] == nums[mid]) && (nums[right] == nums[mid])) { // 无法判断区间 哪个部分是有序的情况
                    left++;
                    right--;
                }else if (nums[left] <= nums[mid]) { // 前半部分有序
                    if (nums[left] <= target && target < nums[mid]) // 元素位于前半部分中
                        right = mid - 1;
                    else // target不在前半段
                        left = mid + 1;
                } else { // 前半部分是无序的则需要分成两部分(有序和无序进行查找)
                    if (nums[mid] < target && target <= nums[right]) // 整个后半部分有序，且target位于之中
                        left = mid + 1;
                    else
                        right = mid - 1;
                }
            }

            return false;
        }
    }
}
